/*
Name: sendmmsgTest.cpp
Author: Sean Sill
Description: A simple test to make sure sendmmsg works correctly
*/

#include <signal.h>
#include <string>
#include <ola/Logging.h>
#include <ola/network/IPV4Address.h>
#include <ola/network/SocketAddress.h>
#include <ola/network/Socket.h>
#include <ola/io/IOQueue.h>

#include <vector>
#include <iostream>
#include <sys/time.h>

using ola::network::UDPSocket;
using ola::network::IPV4SocketAddress;
using ola::network::IPV4Address;
using ola::io::IOQueue;
using std::cout;
using std::string;

static const unsigned char test_cstring[] = "DFDFDFDFDFDFDFDFDFDFDFD";
const uint16_t NUM_TESTS = 100;
const uint16_t NUM_PACKETS = 100;

long test(void) {
  UDPSocket sock;
  
  struct timeval begin;
  struct timeval end;
  long test_time;
  IPV4SocketAddress sock_addr(IPV4Address::WildCard(), 10000);
  
  ola::InitLogging(ola::OLA_LOG_DEBUG, ola::OLA_LOG_STDERR);
  cout << "Begining Sendmmsg Test \n";
  
  // Now lets build a vector of addresses 
  std::vector<IPV4SocketAddress> ip_list;
  for(uint16_t i = 0; i < NUM_PACKETS; i++){
    //ip_list.push_back(IPV4SocketAddress::FromStringOrDie("192.168.1.102:10000"));
    //ip_list.push_back(IPV4SocketAddress::FromStringOrDie("192.168.1.107:10000"));
    ip_list.push_back(IPV4SocketAddress::FromStringOrDie("127.0.0.1:10000"));
  }
  // Attempt to initialize socket
  if(!sock.Init()) {
    OLA_FATAL << "Could not initialize the socket\n";
    return 0;
  }

  // Bind to 0.0.0.0
  if(!sock.Bind(sock_addr)) {
    OLA_FATAL << "Could not bind to: "  << sock_addr << "\n";
  }
  
  
  IOQueue output;
  output.Write(static_cast<const uint8_t*>(test_cstring), sizeof(test_cstring));
 
  /* We only care if sendmmsg is actually decreasing the amount of time we 
       spend in sending multiple of the same packet to many ip addresses*/
  gettimeofday(&begin, NULL);
  ssize_t packets_sent = sock.SendMultipleTo(&output, ip_list);
  gettimeofday(&end, NULL);
  
  test_time = end.tv_usec - begin.tv_usec;
  if(packets_sent < 0){
    OLA_FATAL << "Could not send on  " << sock_addr << "\n";
    return 0;
  }
  
  cout << packets_sent << " packets sent in " << test_time << 
      " microseconds!\n";
  cout << "Closing the socket! Sent " << packets_sent << "packets \n";
  sock.Close();
  
  return test_time; 
}

int main(void) {
  
  std::vector<long> results;
  long avg = 0;

  for(uint16_t i = 0; i < NUM_TESTS; ++i) {
    cout << "*****************************Test " << i << 
        " **************************\n";
    long test_time = test();
    avg += test_time;
    results.push_back(test_time);
  }
  
  avg = avg / results.size();
  cout << "\n\n Completed " << results.size() << 
      " tests with an average time of " << avg << " mircoseconds.\n";

  return 0;
}
